#include "Board.h"

Board::Board()
{
	m_bPattern = new Vector<int>;
	m_bPattern->Init();
	m_clpAllSpecials = new Vector<BaseObject*>;
	m_clpAllSpecials->Init();
	m_clpAllObjects = new DrawList;
	m_clpAllObjects->Init();
	m_bForward = true;
}

Board::~Board()
{
	Delete();
}

const FunctionReturn Board::Init(int const & Size)
{
	m_iSizeType = Size;
	RETURN_CHECK( Create(m_iSizeType) );
	return SUCCEED;
}

//needs a valid world_height and world_width
const FunctionReturn Board::Create(int const & Size)
{
	bool ChangeMapSize = false;
	if(Size != m_iSizeType)
	{
		m_iSizeType = Size;
		ChangeMapSize = true;
	}

	//Create the arrays from scratch if they are nulled out.
	//Resets them to null values if they are not nulled out.
	if(m_clppMyGrid && !ChangeMapSize)
	{
		for(int y = 0;y < m_iSizeType;++y)
		{
			for(int x = 0;x < m_iSizeType;++x)
			{
				m_clppMyGrid[y][x].Clear();
			}
		}
	}
	else
	{
		m_clppMyGrid = new Space*[m_iSizeType];
		for(int y = 0;y < m_iSizeType;++y)
		{
			m_clppMyGrid[y] = new Space[m_iSizeType];
		}

	}
	if(m_iSizeType == SMALL_MAP_SIZE)
		m_iBoardPosMod = SLEFTSIDE;
	if(m_iSizeType == MEDIUM_MAP_SIZE)
		m_iBoardPosMod = MLEFTSIDE;
	if(m_iSizeType == LARGE_MAP_SIZE)
		m_iBoardPosMod = LLEFTSIDE;
	RETURN_CHECK( PlaceBoardTiles(0,0) );
	RETURN_CHECK( PlaceSpecials() );
	RETURN_CHECK( SetListInfo(NULL) );
	return SUCCEED;
}

//Keeps the map in the previous size type but clears out the space information
const FunctionReturn Board::Reset()
{
	RETURN_CHECK( Delete() );
	RETURN_CHECK( Create(m_iSizeType) );
	return SUCCEED;
}

//Sets the map to the new size type
const FunctionReturn Board::Reset(int const & Size)
{
	RETURN_CHECK( Delete() );
	RETURN_CHECK( Create(Size) );
	return SUCCEED;
}

const FunctionReturn Board::Delete()
{
	//deletes everything created by new
	for(int y = 0;y < m_iSizeType;++y)
	{
		delete [] m_clppMyGrid[y];
	}
	delete [] m_clppMyGrid;
	m_bPattern->Clear();

	return SUCCEED;
}

const FunctionReturn Board::PlaceBoardTiles(int const & x,int const & y)
{
	RETURN_CHECK( CheckPattern() );

	static int SetAs = NULL;
	static Space* PrevSpace = NULL;

	while(!m_bBoardCreated)
	{

		SetAs = m_bPattern->get((rand() % m_bPattern->getSize()));
		m_bPattern->remove(SetAs);
		if(PrevSpace)PrevSpace->SetNextSpace(&m_clppMyGrid[y][x]);
		m_clppMyGrid[y][x].CreateSpace(((x*PosMod)+(PosMod/2))+m_iBoardPosMod,((y*PosMod)+(PosMod/2)),(eTileType)SetAs,PrevSpace);
		PrevSpace = &m_clppMyGrid[y][x];

		if(m_bForward == true)
		{
			if(x == m_iSizeType - 1)
			{
				if(y < m_iSizeType - 1)
				{
					m_bForward = false;
					PlaceBoardTiles(x,y+1);
				}
				else m_bBoardCreated = true;
			}
			PlaceBoardTiles(x+1,y);
		}
		else
		{
			if(x == 0)
			{
				if(y < m_iSizeType - 1)
				{
					m_bForward = true;
					PlaceBoardTiles(x,y+1);
				}
				else m_bBoardCreated = true;
			}
			PlaceBoardTiles(x-1,y);
		}
	}
	return SUCCEED;
}

const FunctionReturn Board::PlaceSpecials()
{
#ifdef SPECIALS
	int NumberSpecials = rand() % 11 + 5;
	int SY,SX,EY,EX,Type;
	while(NumberSpecials != NULL)
	{
		
		switch(rand() % 2)
		{
		case 0:
			SY = (rand() % (m_iSizeType - 1) + 1);
			EY = (rand() % SY);
			Type = (int)GEYSER_START;
			break;
		case 1:
			SY = (rand() % (m_iSizeType - 1));
			EY = ((rand() % (m_iSizeType - (SY + 1))) + SY + 1);
			Type = (int)MINECART_START;
			break;
		}
		SX = (rand() % m_iSizeType);
		EX = (rand() % m_iSizeType);

		if(!m_clppMyGrid[SY][SX].IsSpecial() && !m_clppMyGrid[EY][EX].IsSpecial())
		{
			m_clppMyGrid[SY][SX].MakeIntoSpecial(&m_clppMyGrid[EY][EX],(eSpaceType)Type);
			m_clppMyGrid[EY][EX].MakeIntoSpecial(&m_clppMyGrid[SY][SX],(eSpaceType)(Type+1));
			RETURN_CHECK( AddSpecialTiles(SX,SY,EX,EY,(eSpaceType)Type) );
			NumberSpecials--;
		}
	}
#endif
	return SUCCEED;
}

const FunctionReturn Board::AddSpecialTiles(int x1,int y1,int x2,int y2,eSpaceType Type)
{
	eTextureIndex TextIn = TRACK_START;
	if(Type != MINECART_START)
		TextIn = WATER_START;
	float L1,L2;
	L1 = abs((float)x1 - (float)x2);
	L2 = abs((float)y1 - (float)y2);
	double dis = sqrt(pow(L1,(int)2) + pow(L2,(int)2));
	int NumTextures = (int)dis + 1;
	while(NumTextures < 3)	NumTextures++;

	x1 = x1 * PosMod + PosMod/2;
	x2 = x2 * PosMod + PosMod/2;
	y1 = y1 * PosMod + PosMod/2;
	y2 = y2 * PosMod + PosMod/2;

	L1 = abs((float)x1 - (float)x2);
	L2 = abs((float)y1 - (float)y2);

	float Angle = asin(L1/(sqrt((pow(L1,2) + pow(L2,2)))));
	if(x1 > x2)		L1*=-1;
	if(y1 > y2)		L2*=-1;

	if(TextIn == TRACK_START && L1 > 0
		|| TextIn == WATER_START && L1 < 0)
		Angle *=-1;	

	float xPos = (float)x1,yPos = (float)y1;
	
	m_clpAllSpecials->add(new BaseObject(xPos+m_iBoardPosMod,yPos,0,0,Angle,0,TextIn));
	for(int i = 0;i < (NumTextures-1);++i)
	{
		xPos += L1/NumTextures;
		yPos += L2/NumTextures;
		m_clpAllSpecials->add(new BaseObject(xPos+m_iBoardPosMod,yPos,0,0,Angle,0,TextIn+1));
	}
	xPos = (float)x2;yPos = (float)y2;
	m_clpAllSpecials->add(new BaseObject(xPos+m_iBoardPosMod,yPos,0,0,Angle,0,TextIn+2));
	return SUCCEED;
}

const FunctionReturn Board::CheckPattern()
{
	if(!m_bPattern)
		return MISSING_DATA;
	if(m_bPattern->empty())
	{
		ResetPattern();
	}
	return SUCCEED;
}

const FunctionReturn Board::ResetPattern()
{
	if(!m_bPattern)
		return MISSING_DATA;
	for(int i = 0;i < TILE_NULL;++i)
	{
		m_bPattern->add(i);
	}
	return SUCCEED;
}

//Pass NULL to set the values into board's owned list
//Pass a list in to set the values to that list
const FunctionReturn Board::SetListInfo(DrawList* List) const
{
	if(!m_clppMyGrid)
		return MISSING_DATA;
	// Added the check to see if the object list was empty, so it didn't stack every time through.
	// If you have any questions about it let me know Brandon.
	// -Tyler


	m_clppMyGrid[m_iSizeType-1][0].SetLastSpace();
	if(List == NULL) 
	{
		for(int y = 0;y < m_iSizeType;++y)	{
			for(int x = 0;x < m_iSizeType;++x){
				if(&m_clppMyGrid[y][x] && m_clppMyGrid[y][x].m_bDrawing)
				{
					m_clpAllObjects->add(BASEOBJP(m_clppMyGrid[y][x]));
				}
			}
		}
		for(int i = 0;i < m_clpAllSpecials->getSize();++i)
		{
			m_clpAllObjects->add(m_clpAllSpecials->get(i));
		}
		return SUCCEED;
	}
	// This Else statement was crashing everytime it ran through. Not sure if it was a proper fix or if it had another purpose

	else
	{
		for(int y = 0;y < m_iSizeType;++y)	{
			for(int x = 0;x < m_iSizeType;++x){
				if(&m_clppMyGrid[y][x] && m_clppMyGrid[y][x].m_bDrawing)
					List->add(BASEOBJP(m_clppMyGrid[y][x]));
			}
		}
		
		for(int i = 0;i < m_clpAllSpecials->getSize();++i)
		{
			List->add(m_clpAllSpecials->get(i));
		}
		return SUCCEED;
	}
	return UNKNOWN;
}